#ifndef DSPNASM_OPERAND_H
#define DSPNASM_OPERAND_H

#include <bitset>
#include "nasm/type/type.h"
#include "nasm/operand/register.h"

namespace dspnasm {
    enum class OperandKind {
        UN_KNOWN,
        IMMEDIATE,
        DOUBLE_REGISTER,
        SINGLE_REGISTER,
        MEMORY
    };

    class Operand {
    protected:
        OperandKind m_operandKind;
    public:
        Operand(OperandKind operandKind) :
                m_operandKind(operandKind) {}

        virtual ~Operand() = default;
    };

    class ImmediateOp : public Operand {
    public:
        u32 m_data;

        ImmediateOp(u32 data) :
                Operand(OperandKind::IMMEDIATE), m_data(data) {}

        ~ImmediateOp() override = default;
    };

    class DoubleRegOp : public Operand {
    public:
        RegKind m_regLo;
        RegKind m_regHi;

        DoubleRegOp(const std::string &regLo, const std::string &regHi) :
                Operand(OperandKind::DOUBLE_REGISTER), m_regLo(getRegKind(regLo)), m_regHi(getRegKind(regHi)) {}

        ~DoubleRegOp() override = default;
    };

    class SingleRegOp : public Operand {
    public:
        RegKind m_reg;

        SingleRegOp(const std::string &reg) :
                Operand(OperandKind::SINGLE_REGISTER), m_reg(getRegKind(reg)) {}

        ~SingleRegOp() override = default;
    };

    class MemoryOp : public Operand {
    public:
        std::bitset<4> m_mode;
        RegKind m_baseR;
        RegKind m_offsetR;
        std::bitset<5> m_ucst5;

        MemoryOp(const std::bitset<4> &mode, RegKind baseR, RegKind offsetR) :
                Operand(OperandKind::MEMORY), m_mode(mode), m_baseR(baseR), m_offsetR(offsetR), m_ucst5(0) {}

        MemoryOp(const std::bitset<4> &mode, RegKind baseR, const std::bitset<5> &ucst5) :
                Operand(OperandKind::MEMORY), m_mode(mode), m_baseR(baseR), m_offsetR(RegKind::UN_KNOWN),
                m_ucst5(ucst5) {}

        ~MemoryOp() override = default;
    };
}


#endif //DSPNASM_OPERAND_H
